<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <style>
    header {
      text-align: center;
      font-size: 24px;
      font-weight: 600;
    }
    li {
      margin: 20px;
    }
  </style>
  <ul>
    <li>
      <header>Set和Map</header>
      <li>
        Set 和 Map 是 ES6 中新增的两种数据结构。
      </li>
      <li>
        Set 是一种无序的、不重复的集合，其中的元素唯一，可以用于数组去重,不能通过下标访问元素，但可以使用 for...of 循环来遍历元素
      </li>
      <li>
        Map 是一种键值对的集合，其中的键和值可以是任意类型的数据。Map 中的元素按照插入顺序进行迭代
      </li>
      <li>
        Set 和 Map 的区别在于：
        <li>Set 只存储键值，而 Map 存储键值对。</li>
        <li>Set 中的键和值是相同的，而 Map 中的键和值可以是不同的。</li>
        <li>Set 是一种集合，没有重复的元素，而 Map 是一种键值对集合，可以有重复的值。</li>
      </li>
    </li>
    <li>
      <header>闭包是什么?</header>
        <ul>
          <li>
            闭包是js的一种语法特性，当一个函数能够访问到在其外部定义的变量时，就产生了闭包。
          </li>
          <li>
            <img src="./img/屏幕截图 2023-04-10 181626.png" alt="">
          </li>
          <li>
            例如，，创建一个立即执行函数，在这个立即执行函数内部声明一个变量count，再声明一个add函数，此函数内部是count += 1，然后return add函数
          </li>
          <li>
            然后我们声明一个add2变量就等于这个立即执行函数
          </li>
          <li>
            此时调用add2就相当于调用add,它操作了立即执行函数的count变量
          </li>
          <li>
            这个count+add的整体就是一个闭包
          </li>
          <li>
            闭包的解决的问题是：
            避免污染全局变量，
            提供了对局部变量的访问，
            维持这个变量不会被垃圾回收
          </li>
          <li>
            闭包的缺点是使用不可能造成内存泄漏
          </li>
          <li>
            比如说在一个函数内部声明两个很大的对象，我们返回的函数只使用了其中一个，另一个变量就会一直在内存中，导致内存泄漏
          </li>
          <li>
            <img src="./img/屏幕截图 2023-04-10 181835.png" alt="">
          </li>
        </ul> 
    </li>
    <li>
      <header>js的作用域链</header>
      <li>
        作用域链是指在 JavaScript 中，每个执行上下文（Execution Context）中包含一个变量对象（Variable Object）列表，这些变量对象构成的链表就是作用域链。
      </li>
      <li>比如说： 一个函数嵌套了其他函数，那么里面的函数要访问外部函数的变量，它先找自己作用域有没有这个变量，如果没有，它会沿着作用域链查找，直到全局作用域</li>
    </li>
    <li>
      作用域链的主要优点就是能够实现变量的嵌套作用域和继承
    </li>

    <li>
      <header>async await的原理是什么?</header>
      <li>
        async/await 是 JavaScript 中用于异步编程的语法糖，它的原理是基于 Promise 对象实现的。
      </li>
      <li>
        比如说：当使用 async 关键字修饰一个函数时，这个函数就会返回一个 Promise 对象。如果这个函数中有 await 关键字，那么在遇到 await 关键字时，函数会暂停执行，并返回一个未完成状态（Pending）的 Promise 对象
      </li>
      <li>
        异步函数中的 await 关键字会将后面的 Promise 对象包装成一个微任务，并加入到微任务队列中，等到微任务队列中的任务全部执行完毕后，再继续执行异步函数的后续代码
      </li>
      <li>
        async await的优点就是让异步代码看起来和同步代码差不多，代码可读性更强
      </li>
      <li>
        缺点就是不支持太老的浏览器
      </li>
    </li>

    -------------------------------------------------------------------------
    <li>
      <header>js中的事件循环</header>

      <ul>
        <li>
          js维护一个执行栈和一个任务队列
        </li>
        <li>
          同步任务都会被放进执行栈中按照顺序执行，而所有的异步任务都会被放进任务队列中等待执行。
        </li>
        <li>
          当执行栈中的所有同步任务执行完毕后，JavaScript引擎就会去查看任务队列中是否有任务，如果有，就将任务队列中的第一个任务取出放到执行栈中执行。这个过程不断重复，从而实现了异步操作的执行。这就是一个事件循环
        </li>
        <li>
          在事件循环中，任务队列又分为宏任务（Macrotask）和微任务（Microtask）两种，它们的执行顺序也是有规定的。在执行栈中的同步任务执行完毕后，会先执行所有的微任务，然后再执行宏任务。
        </li>
        <li>
          比如setTimeout，uI交互click之类的就是宏任务
        </li>
        <li>
          Promise.then,或者window.queueMicrotask之类的就可以创建微任务
        </li>
      </ul>
    </li>
  </ul>
</body>
</html>